﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure;
using Canyala.Lagoon.IO;

namespace Canyala.Lagoon.Test
{
    [TestClass]
    public class PageBlobStreamTest
    {
        [TestMethod]
        public void CreateStreamReadonlyTest()
        {
            var blob = CreateTestPageBlob(1024);
            try
            {
                var pbs = PageBlobStream.Create(blob, readOnly: true);
                Assert.IsTrue(pbs.CanRead && !pbs.CanWrite);
            }
            finally
            {
                blob.DeleteIfExists();
            }    
        }

        [TestMethod]
        public void CreateStreamTest()
        {
            var blob = CreateTestPageBlob(1024);
            try
            {
                using (var pbs = PageBlobStream.Create(blob, readOnly: false))
                    Assert.IsTrue(pbs.CanRead && pbs.CanWrite);
            }
            finally
            {
                blob.DeleteIfExists();
            }
        }

        [TestMethod]
        public void WriteAndReadTest()
        {
            var blob = CreateTestPageBlob(1024);
            try
            {
                byte[] data = GenerateSampleData(1024);
                using (var pbs = PageBlobStream.Create(blob, readOnly: false))
                {
                    pbs.Write(data, 0, 1024);
                    pbs.Flush();
                    pbs.Position = 0;
                    byte[] actual = new byte[1024];
                    pbs.Read(actual, 0, 1024);

                    CollectionAssert.AreEqual(data, actual);
                }
            }
            finally
            {
                blob.DeleteIfExists();
            }
        }

        [TestMethod]
        public void WriteAndReadBigDataTest()
        {
            var size = 1024 * 1024 * 8;
            CloudPageBlob writeBlob = CreateTestPageBlob(size);
            CloudPageBlob readBlob = null;
            try
            {
                byte[] data = GenerateSampleData(size);
                using (var pbs = PageBlobStream.Create(writeBlob, cacheSize: 4 * 1024 * 1024))
                {
                    pbs.Write(data, 0, size);
                    pbs.Flush();
                }

                readBlob = OpenTestPageBlob(size);
                using (var pbs = PageBlobStream.Create(readBlob, cacheSize: 4 * 1024 * 1024, readOnly: true))
                {
                    pbs.Position = 0;
                    byte[] actual = new byte[size];
                    pbs.Read(actual, 0, size);

                    CollectionAssert.AreEqual(data, actual);    
                }
            }
            finally
            {
                writeBlob.DeleteIfExists();
                if (readBlob != null)
                    readBlob.DeleteIfExists();
            }
        }

        [TestMethod]
        public void PositionUpdateAfterReadTest()
        {
            var size = 1024;
            var blob = CreateTestPageBlob(size);
            try
            {
                byte[] data = GenerateSampleData(size);
                using (var pbs = PageBlobStream.Create(blob, cacheSize: 4 * 1024 * 1024))
                {
                    pbs.Write(data, 0, size);
                    pbs.Flush();
                    pbs.Position = 0;
                    byte[] actual = new byte[size];
                    pbs.Read(actual, 0, size/2);

                    Assert.AreEqual(size/2, pbs.Position);
                }
            }
            finally
            {
                blob.DeleteIfExists();
            }
        }

        [TestMethod]
        public void PositionUpdateAfterWriteTest()
        {
            var size = 1024;
            var blob = CreateTestPageBlob(size);
            try
            {
                byte[] data = GenerateSampleData(size);
                using (var pbs = PageBlobStream.Create(blob, cacheSize: 4 * 1024 * 1024))
                {
                    pbs.Write(data, 0, size/2);
                    pbs.Flush();

                    Assert.AreEqual(size / 2, pbs.Position);
                }
            }
            finally
            {
                blob.DeleteIfExists();
            }
        }

        #region helpers

        private static byte[] GenerateSampleData(int size)
        {
            var bytes = new byte[size];

            for (int i = 0; i < size; i++)
            {
                bytes[i] = (byte)(i % byte.MaxValue);
            }

            return bytes;
        }

        private static CloudPageBlob CreateTestPageBlob(long maximumSizeInBytes)
        {
            var account = CloudStorageAccount.DevelopmentStorageAccount;
            var container = account.CreateCloudBlobClient().GetContainerReference("testcontainer");
            container.CreateIfNotExist();
            var blob = container.GetPageBlobReference("testblob");
            blob.Create(maximumSizeInBytes);

            return blob;
        }

        private static CloudPageBlob OpenTestPageBlob(long maximumSizeInBytes)
        {
            var account = CloudStorageAccount.DevelopmentStorageAccount;
            var container = account.CreateCloudBlobClient().GetContainerReference("testcontainer");
            container.CreateIfNotExist();
            var blob = container.GetPageBlobReference("testblob");
            
            return blob;
        }

        #endregion
    }
}
